package com.zhxy.util.service.auth;

import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

import com.zhxy.util.api.auth.Authentication;
import com.zhxy.util.api.auth.Certificate;
import com.zhxy.util.api.auth.NamePwdCertificate;
import com.zhxy.util.api.auth.Permission;
import com.zhxy.util.api.cache.Cache;
import com.zhxy.util.api.cache.ExtendedCache;

/**
 * 实现了用户名密码验证的主要功能
 * @author 刘勉
 *
 */
public abstract class NamePwdAuthentication implements Authentication {

	private static final LocalPermissionSession ANONYMOUS = new LocalPermissionSession();
	
	private Cache cache;
	
	/** 超时时间，单位秒 */
	private long expires = 0;
	
	
	/** 总的验证成功次数 */
	private AtomicLong totalAuthenticateCount = new AtomicLong();
	
	/** 总获取Session成功次数 */
	private AtomicLong totalGetSessionCount = new AtomicLong();
	
	/** 总获取Session失败次数 */
	private AtomicLong totalMissSessionCount = new AtomicLong();
	
	/** 总查询权限成功次数 */
	private AtomicLong totalQueryPermissionCount = new AtomicLong();
	
	/** 总命中权限缓存次数 */
	private AtomicLong totalHitPermissionCacheCount = new AtomicLong();


	public void setCache(ExtendedCache cache) {
		this.cache = cache;
	}

	public long getExpires() {
		return expires;
	}

	public void setExpires(long expires) {
		this.expires = expires;
	}

	public long getTotalAuthenticateCount() {
		return totalAuthenticateCount.get();
	}

	public long getTotalGetSessionCount() {
		return totalGetSessionCount.get();
	}

	public long getTotalMissSessionCount() {
		return totalMissSessionCount.get();
	}

	public long getTotalQueryPermissionCount() {
		return totalQueryPermissionCount.get();
	}

	public long getTotalHitPermissionCacheCount() {
		return totalHitPermissionCacheCount.get();
	}

	public long onlines() {
		return cache.size();
	}
	
	@Override
	public String authenticate(Certificate cert) {

		NamePwdCertificate auth = (NamePwdCertificate)cert;
		if (auth == null || auth.getName() == null
				|| auth.getPassword() == null) {
			return null;
		}

		UserData data = getUserData(auth);
		if (data == null)
			return null;
		String token = UUID.randomUUID().toString();
		AuthSession session = new AuthSession();
		session.data = data;
		session.permission = new AtomicReference<Set<String>>();
		cache.put(token, session, expires);
		
		totalAuthenticateCount.addAndGet(1);
		
		return token;
	}

	@Override
	public void invalid(String token) {
		cache.remove(token);
	}

	@Override
	public Permission queryPermission(String token) {
		
		if (token == null)
			return ANONYMOUS;
		AuthSession session = (AuthSession)cache.get(token);
		if (session == null) {
			totalMissSessionCount.addAndGet(1);
			return ANONYMOUS;
		}
		UserData data = session.data;

		LocalPermissionSession cert = new LocalPermissionSession(this);
		cert.setId(data.getId());
		cert.setToken(token);
		cert.setName(data.getName());
		
		totalGetSessionCount.addAndGet(1);

		return cert;
	}

	public Set<String> queryPermissions(String token) {
		
		AuthSession session = (AuthSession)cache.get(token);
		if (session == null)
			return null;
		UserData data = session.data;

		boolean hitCache = true;
		// 使用double check防止重复请求权限
		if (session.permission.get() == null) {
			synchronized (session.permission) {
				if (session.permission.get() == null) {
					session.permission.set(getPermission(data.getId()));
					hitCache = false;
				}
			}
		}
		
		if (hitCache)
			totalHitPermissionCacheCount.addAndGet(1);
		totalQueryPermissionCount.addAndGet(1);
		
		return session.permission.get();
	}
	
	abstract protected UserData getUserData(NamePwdCertificate cert);
	
	abstract protected Set<String> getPermission(String id);

	class AuthSession {
		public UserData data;
		public AtomicReference<Set<String>> permission;
	}
}
